package com.ruibang.glass.quality.service;


import com.google.common.collect.Lists;
import com.ruibang.glass.quality.domain.resp.SpcXbarAbnormalJudgment;
import com.ruibang.glass.quality.constant.XbarAbnormalJudgeEnums;
import com.ruibang.glass.quality.util.spc.SPCUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: songJinKang
 * @CreateTime: 2023-10-19  16:55
 * @Description: TODO
 * @Version: 1.0
 */
public class SPCTest {

    private static final double[] datas = {
            1,
            2,
            3,
            4,
            5,
            6,
            6,
            7,
            8,
            9,
            10,
            11,
            12,
            13,
            14,
            15,
            1,
            2,
            3,
            4,
            5,
            6,
            7,
            8,
            9,
            30,
            30,
            30,
            30,
            30,
            30,
            30,
            30,
            30,
            30,
            30,};


    public static void main(String[] args) {
        List<BigDecimal> bigDecimal = new ArrayList<>();
        for (double data : datas) {
            bigDecimal.add(new BigDecimal(data));
        }
        List<SpcXbarAbnormalJudgment> spcXbarAbnormalJudgments = new ArrayList<>();
        SpcXbarAbnormalJudgment spcXbarAbnormalJudgment = new SpcXbarAbnormalJudgment();
        spcXbarAbnormalJudgment.setStandardCode(8);
        spcXbarAbnormalJudgment.setKValue(8);
        spcXbarAbnormalJudgment.setSelectFlag(1);
        spcXbarAbnormalJudgments.add(spcXbarAbnormalJudgment);

        List<Integer> list = abnormalJudgment(bigDecimal, spcXbarAbnormalJudgments);
        System.out.println(list);
    }


    /**
     * @Description: 判异
     * @version v1.0
     * @author songJinKang
     * @date 2023-10-23 1:52
     */
    public static List<Integer> abnormalJudgment(List<BigDecimal> datas, List<SpcXbarAbnormalJudgment> spcXbarAbnormalJudgments) {
        // 用于存储异常数据的下标
        List<Integer> abnormalDataIndexs = Lists.newArrayList();

        // 基础数据
        //中心线-总均值
        BigDecimal avgX = SPCUtils.average(datas);
        //标准差
        BigDecimal standardDiviation = SPCUtils.standardDiviation(datas);
        spcXbarAbnormalJudgments = spcXbarAbnormalJudgments.stream().filter(
                spcXbarAbnormalJudgment -> XbarAbnormalJudgeEnums.selectFlag.YES.getCode().equals(spcXbarAbnormalJudgment.getSelectFlag())
        ).collect(Collectors.toList());


        // 数据计算容器
        // 1：中心线上方。-1：中心线下方 （标准2）
        int twoDirection = 1;
        // 累计异常数据下标（标准2）
        List<Integer> twoAbnormalIndex = Lists.newArrayList();
        // 1：上升   -1：下降 （标准3）
        int threeDirection = 1;
        // 累计异常数据下标（标准3）
        List<Integer> threeAbnormalIndex = Lists.newArrayList();
        // 1：上升   -1：下降 （标准4）
        int fourDirection = 1;
        // 累计异常数据下标（标准4）
        List<Integer> fourAbnormalIndex = Lists.newArrayList();
        // 累计异常数据下标（标准7）
        List<Integer> sevenAbnormalIndex = Lists.newArrayList();
        // 累计异常数据下标（标准8）
        List<Integer> eightAbnormalIndex = Lists.newArrayList();

        for (int i = 0; i < datas.size(); i++) {
            BigDecimal data = datas.get(i);
            for (SpcXbarAbnormalJudgment abnormalJudgment : spcXbarAbnormalJudgments) {
                BigDecimal k = new BigDecimal(abnormalJudgment.getKValue());
                switch (XbarAbnormalJudgeEnums.type.getByCode(abnormalJudgment.getStandardCode())) {
                    // 一个点，距离中心线大于K个标准差
                    case ONE:
                        if (data.compareTo(k.multiply(standardDiviation)) > 0) {
                            abnormalDataIndexs.add(i);
                        }
                        break;

                    // 连续K个点在中心线同一侧
                    case TWO:
                        if (k.intValue() > 1) {
                            if (i == 0) {
                                twoDirection = data.compareTo(avgX) > 0 ? 1 : -1;
                                twoAbnormalIndex.add(i);
                            } else {
                                // 跟上个数据在同一侧，累加
                                if ((data.compareTo(avgX) > 0 && twoDirection > 0) || (data.compareTo(avgX) < 0 && twoDirection < 0)) {
                                    twoAbnormalIndex.add(i);
                                    //第一次到达阈值，把前面符合条件的数据都存入警告集合；
                                    if (twoAbnormalIndex.size() == k.intValue()) {
                                        abnormalDataIndexs.add(twoAbnormalIndex.get(twoAbnormalIndex.size() - 1));
                                    } else if (twoAbnormalIndex.size() > k.intValue()) {
                                        abnormalDataIndexs.add(i);
                                    }
                                }
                                // 不符合报警条件，归零重新计算
                                else {
                                    twoDirection = data.compareTo(avgX) > 0 ? 1 : -1;
                                    twoAbnormalIndex.clear();
                                    twoAbnormalIndex.add(i);
                                }
                            }
                        }
                        break;
                    // 连续K个点， 全部递增或全部递减
                    case THREE:
                        if (k.intValue() > 1) {
                            // 判断方向至少需要两个点，初始值默认要存两个，从第三个开始判断是否递增递减；
                            if (i < 2) {
                                threeAbnormalIndex.add(i);
                            } else {
                                // 跟上个数据同个趋势，累加
                                if ((data.compareTo(datas.get(i - 1)) > 0 && threeDirection > 0) || (data.compareTo(datas.get(i - 1)) < 0 && threeDirection < 0)) {
                                    threeAbnormalIndex.add(i);
                                    //第一次到达阈值，把前面符合条件的数据都存入警告集合；
//                                    if (threeAbnormalIndex.size() == k.intValue()) {
//                                        abnormalDataIndexs.add(threeAbnormalIndex.get(threeAbnormalIndex.size() - 1));
//                                    } else if (threeAbnormalIndex.size() > k.intValue()) {
//                                        abnormalDataIndexs.add(i);
//                                    }
                                    if (threeAbnormalIndex.size() > k.intValue()) {
                                        abnormalDataIndexs.add(threeAbnormalIndex.get(threeAbnormalIndex.size() - 1));
                                    }
                                }
                                // 不符合报警条件，归零重新计算
                                else {
                                    threeDirection = data.compareTo(datas.get(i - 1)) > 0 ? 1 : -1;
                                    threeAbnormalIndex.clear();
                                    threeAbnormalIndex.add(i - 1);
                                    threeAbnormalIndex.add(i);
                                }
                            }
                        }
                        break;
                    // 连续K个点，上下交接
                    case FOUR:
                        if (k.intValue() > 1) {
                            if (i < 2) {
                                // 判断方向至少需要两个点，初始值默认要存两个，从第三个开始判断是否递增递减；
                                fourAbnormalIndex.add(i);
                            } else {
                                // 跟上个数据不同趋势，累加
                                if ((data.compareTo(datas.get(i - 1)) > 0 && fourDirection < 0) || (data.compareTo(datas.get(i - 1)) < 0 && fourDirection > 0)) {
                                    // 方向重置
                                    fourDirection = data.compareTo(datas.get(i - 1)) > 0 ? 1 : -1;
                                    fourAbnormalIndex.add(i);
                                    //第一次到达阈值，把前面符合条件的数据都存入警告集合；
//                                    if (fourAbnormalIndex.size() == k.intValue()) {
//                                        abnormalDataIndexs.add(fourAbnormalIndex.get(fourAbnormalIndex.size() - 1));
//                                    } else if (fourAbnormalIndex.size() > k.intValue()) {
//                                        abnormalDataIndexs.add(i);
//                                    }
                                    if (fourAbnormalIndex.size() > k.intValue()) {
                                        abnormalDataIndexs.add(fourAbnormalIndex.get(fourAbnormalIndex.size() - 1));
                                    }
                                }
                                // 不符合报警条件，归零重新计算
                                else {
                                    fourDirection = data.compareTo(datas.get(i - 1)) > 0 ? 1 : -1;
                                    fourAbnormalIndex.clear();
                                    fourAbnormalIndex.add(i - 1);
                                    fourAbnormalIndex.add(i);
                                }
                            }
                        }
                        break;
                    // K+1个点中有K个点，距离中心线（同侧）大于2个标准差
                    case FIVE:
                        // 中心线上方累计异常数据下标（标准5）
                        List<Integer> fiveUpAbnormalIndex = Lists.newArrayList();
                        // 中心线下方累计异常数据下标（标准5）
                        List<Integer> fiveDownAbnormalIndex = Lists.newArrayList();
                        // 从第K个值开始统计，往前遍历是否有K-1个值符合条件
                        if (i >= k.intValue() - 1) {
                            for (int j = 0; j < k.intValue(); j++) {
                                double dData = datas.get(i - j).doubleValue();
                                if (dData > standardDiviation.doubleValue() * 2) {
                                    if (dData >= avgX.doubleValue()) {
                                        fiveUpAbnormalIndex.add(i - j);
                                    } else {
                                        fiveDownAbnormalIndex.add(i - j);
                                    }
                                }
                            }
                            if (fiveUpAbnormalIndex.size() >= k.intValue()) {
                                abnormalDataIndexs.add(fiveUpAbnormalIndex.get(0));
                            }
                            if (fiveDownAbnormalIndex.size() >= k.intValue()) {
                                abnormalDataIndexs.add(fiveDownAbnormalIndex.get(0));
                            }
                        }
                        break;
                    // K+1个点中有K个点，距离中心线（同侧）大于1个标准差
                    case SIX:
                        // 中心线上方累计异常数据下标（标准6）
                        List<Integer> sixUpAbnormalIndex = Lists.newArrayList();
                        // 中心线下方累计异常数据下标（标准6）
                        List<Integer> sixDownAbnormalIndex = Lists.newArrayList();
                        // 从第K个值开始统计，往前遍历是否有K-1个值符合条件
                        if (i >= k.intValue() - 1) {
                            for (int j = 0; j < k.intValue(); j++) {
                                double dData = datas.get(i - j).doubleValue();
                                if (dData > standardDiviation.doubleValue()) {
                                    if (dData >= avgX.doubleValue()) {
                                        sixUpAbnormalIndex.add(i - j);
                                    } else {
                                        sixDownAbnormalIndex.add(i - j);
                                    }
                                }
                            }
                            if (sixUpAbnormalIndex.size() >= k.intValue()) {
                                abnormalDataIndexs.add(sixUpAbnormalIndex.get(0));
                            }
                            if (sixDownAbnormalIndex.size() >= k.intValue()) {
                                abnormalDataIndexs.add(sixDownAbnormalIndex.get(0));
                            }
                        }
                        break;
                    // 连续K个点，距离中心线（任一侧）1个标准差以内
                    case SEVEN:
                        if (data.compareTo(standardDiviation) < 0) {
                            sevenAbnormalIndex.add(i);
                            //第一次到达阈值，把前面符合条件的数据都存入警告集合；
                            if (sevenAbnormalIndex.size() == k.intValue()) {
                                abnormalDataIndexs.addAll(sevenAbnormalIndex);
                            } else if (sevenAbnormalIndex.size() > k.intValue()) {
                                abnormalDataIndexs.add(i);
                            }
                        }
                        // 不符合报警条件，归零重新计算
                        else {
                            sevenAbnormalIndex.clear();
                        }
                        break;

                    // 连续K个点，距离中心线（任一侧）大于1个标准差
                    case EIGHT:
                        if (data.compareTo(standardDiviation) > 0) {
                            eightAbnormalIndex.add(i);
                            //第一次到达阈值，把前面符合条件的数据都存入警告集合
                            if (eightAbnormalIndex.size() == k.intValue()) {
                                abnormalDataIndexs.add(eightAbnormalIndex.get(eightAbnormalIndex.size() - 1));
                            } else if (eightAbnormalIndex.size() > k.intValue()) {
                                abnormalDataIndexs.add(i);
                            }
                        }
                        // 不符合报警条件，归零重新计算
                        else {
                            eightAbnormalIndex.clear();
                        }
                        break;
                    default:
                        break;
                }
            }
        }
        Collections.sort(abnormalDataIndexs);
        return abnormalDataIndexs;
    }

}
